![]() |
![]() |
|
Die ElementaktivierungDie Listenansicht bietet eine stattliche Anzahl Eigenschaften, um die Anzeige des Steuerelements zu gestalten und dem Benutzer bestimmte Bedienfunktionen zu ermöglichen. Mit AllowColumnRecorder=true gestatten wir einem Anwender beispielsweise, die Reihenfolge der Spalten zu verändern, HoverSelection=true erlaubt die Auswahl eines Elements ohne Mausklick, und MultiSelect=true gibt an, ob mehrere Listeneinträge gleichzeitig ausgewählt werden dürfen. Bei einer Listenansicht muss genau zwischen Aktivierung und Auswahl unterschieden werden. Ein Listenelement wird standardmäßig ausgewählt, wenn mit der Maus einmal auf das Element geklickt wird oder die Auswahl mit den Pfeiltasten verändert wird. Aktiviert wird ein Listenelement, wenn durch einen Doppelklick eine Programmaktion gestartet wird. Das ist zumindest der Standard. Manchmal ist es wünschenswert, vom Standardverhalten abweichend eine andere Aktivierung vorzusehen. Dazu dient die Eigenschaft Activation. Drei Möglichkeiten, die der folgenden Tabelle entnommen werden können, werden von der Enumeration ItemActivation angeboten.
Die wichtigsten spezifischen Eigenschaften einer ListenansichtDie folgende Tabelle gibt einen Überblick über die wichtigsten Eigenschaften einer Listenansicht. Einige Eigenschaften werden im weiteren Verlauf des Abschnitts noch einmal erwähnt.
Die Ereignisse des »ListView«-SteuerelementsEs sind nicht wenige Ereignisse, die eine ListView dem Entwickler anbietet. Ich möchte Ihnen hier nur drei steuerelementspezifische Ereignisse vorstellen, die besonders erwähnenswert sind:
Die beiden zuerst angeführten Ereignisse sind vom Typ EventHandler. Das bedeutet, dass dem Ereignishandler keine weiteren Informationen zur Verfügung gestellt werden. ColumnClick ist dagegen schon mitteilungsbedürftiger: Der Typ ColumnClickEventArgs liefert in der Eigenschaft Column den Index der angeklickten Spalte. 19.15.3 Listenelemente vom Typ »ListViewItem«
|
|||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||||
| lvwPerson.Items.Add(new ListViewItem("Abel")); |
| lvwPerson.Items.Add(new ListViewItem("Müller")); |
| lvwPerson.Items.Add(new ListViewItem("Rosnick")); |
| lvwPerson.Items.Add(new ListViewItem(“Berenbach")); |
| lvwPerson.Items.Add(new ListViewItem("Keser")); |
Hier ist lvwPerson das ListView-Objekt. Sie müssen nicht unbedingt ausdrücklich die Klasse ListViewItem instanziieren. Sie können als Argument auch eine Zeichenfolge übergeben:
| listView1.Items.Add("Müller"); |
Ein Listenelement kann durch spezifische Eigenschaften beschrieben werden. Jede Eigenschaft, auch als Unterelement bezeichnet, wird durch ein Objekt vom Typ ListViewSubItem beschrieben. Alle Unterelemente sind ebenfalls nur Zeichenfolgen und werden von der Auflistung ListViewSubItemCollection des Listenelements verwaltet. Durch den Aufruf der Methode SubItems auf die Referenz eines Listenelements erhält man die Referenz auf die untergeordnete ListViewSubItemCollection. Die folgende Anweisung schreibt beispielsweise Bonn in die Zeichenfolgevariable item:
| string item = lvwPerson.Items[2].SubItems[3].Text; |
In den beiden Ansichten Große Symbole und Kleine Symbole können die Listenelemente über die entsprechende Einstellung der Eigenschaft View zur Laufzeit optisch ansprechend und übersichtlich dargestellt werden. Dazu sind der Form zwei ImageList-Steuerelemente hinzuzufügen, welche die gewünschten Symbole enthalten.
Außerdem kann ein Listenelement, unabhängig von der gewählten Ansicht, zur Laufzeit auch ein Bildchen anzeigen, das den ausgewählten bzw. nicht ausgewählten Zustand symbolisieren soll. Um Zustandssymbole anzubieten, sind einige Vorgaben einzuhalten. Zunächst müssen Sie der Form eine weitere Bildliste hinzufügen, in der nur zwei Symbole enthalten sein sollten: Das erste Bild mit dem Index 0 wird vor den nicht ausgewählten Listenelementen anzeigt, das Bild mit dem Index 1 vor den ausgewählten. Anschließend weisen Sie der Eigenschaft StateImageList des ListView-Objekts die Referenz auf diese Bildliste zu. Im letzten Schritt muss die Eigenschaft CheckBoxes=true gesetzt werden, denn Zustandssymbole ersetzen die Checkboxen.
Damit sind aber möglicherweise noch nicht alle Anforderungen erfüllt. Jedes ListViewItem-Objekt hat eine Eigenschaft StateImageIndex, die den aktuellen Index des angezeigten Symbols in der Bildliste beschreibt. Wenn Sie möchten, können Sie hier auch die Reihenfolge in der Bilderliste umkehren. Zur Laufzeit steht der Index des Bildes in direktem Zusammenhang zur Eigenschaft Checked des Listenelements.
Zur Laufzeit genügt ein Klick auf das Symbol, um ein Listenelement auszuwählen beziehungsweise den ausgewählten Zustand zurückzuversetzen. Dabei wechselt das Symbol automatisch.
In einer Listenansicht kann per Vorgabe entweder ein Element oder auch mehrere ausgewählt werden. Mit der Eigenschaft MultiSelect der Listenansicht wird das festgelegt. Die Standardeinstellung ist true.
Die Eigenschaft Selected eines Listenelements beschreibt den Auswahlzustand und kann nicht nur gelesen, sondern auch gesetzt werden, beispielsweise um bei der ersten Anzeige der Listenansicht bereits eine Vorauswahl getroffen zu haben.
Insbesondere wenn eine Mehrfachauswahl möglich ist, müssen zu einem bestimmten Zeitpunkt alle ausgewählten Listenelemente mittels Programmcode ermittelt werden, um darauf die erforderlichen Operationen ausführen zu können. ListView stellt daher, ähnlich wie eine ListBox, zwei Auflistungen bereit:
| SelectedIndexCollection |
| SelectedListViewItemCollection |
Beide Auflistungsklassen unterscheiden sich untereinander nur darin, wie die ausgewählten Listenelemente verwaltet werden.
| SelectedIndexCollection enthält die Indizes der ausgewählten Listenelemente. |
| SelectedListViewItemCollection enthält die Referenzen auf die ausgewählten Listenelemente. |
Um die beiden Auflistungen auszuwerten, bedarf es jeweils einer Eigenschaft: SelectedIndices und SelectedItems. Über welche Auflistung man auf ein ausgewähltes Listenelement zugreift (dafür gibt es in beiden Auflistungen einen Indexer), dürfte wohl eher eine Geschmacksfrage sein, als auf einer Notwendigkeit basieren. Sie bekommen in jedem Fall die Referenzen auf die ausgewählten Listenelemente zurückgeliefert, um damit die erforderlichen Operationen auszuführen.
Die folgende Anweisung liest die Text-Eigenschaft des ersten ausgewählten Elements über den Indexer ein und gibt sie in einem Meldungsfenster aus:
| MessageBox.Show(listView1.SelectedItems[0].Text); |
Die Unterelemente eines ListViewItem-Objekts werden durch die innere Klasse ListViewSubItem beschrieben. Jedes Unterelement wird durch eine Zeichenfolge beschrieben. Verwaltet werden die Unterelemente in der Auflistung ListViewSubItemCollection. An dieser Stelle muss noch einmal darauf hingewiesen werden, dass das erste Unterelement mit der Indexposition 0 in der ListViewSubItemCollection immer das Element ist, das die Unterelemente besitzt. Wenn Sie alle Unterelemente abfragen wollen, müssen Sie demnach die Auflistung vom Index 1 an durchlaufen und nicht vom Index 0.
Unterelemente können Sie durch Aufruf des Konstruktors der Klasse erzeugen. Am geeignetsten ist dazu der Konstruktor, dem neben der beschreibenden Zeichenfolge im ersten Argument die Referenz auf das Listenelement übergeben wird, dem das neue Unterelement zugeordnet werden soll.
| public ListViewSubItem(ListViewItem, string); |
Sie können bei der Erzeugung eines Listenelements auch sofort die Eigenschaften, also Unterelemente, festlegen. Benutzen Sie dazu bei der Instanziierung der Klasse ListViewItem einen Konstruktor, der ein Zeichenfolge-Array entgegennimmt, werden alle Array-Elemente automatisch der Auflistung der Unterelemente hinzugefügt.
Etwas ungewöhnlich ist die Tatsache, dass sich jedes ListViewItem-Objekt nicht nur in die Auflistung ListViewItemCollection der Listenansicht einträgt, sondern gleichzeitig auch das erste Element in seiner eigenen ListViewSubItemCollection ist.
| lvwPerson.Items.Add(new ListViewItem(new string[] |
| {"Abel","Rainer", "30", "Essen"})); |
| lvwPerson.Items.Add(new ListViewItem(new String[] |
| {"Müller", "Uwe", "25", "Berlin"})); |
| lvwPerson.Items.Add(new ListViewItem(new String[] |
| {"Rosnick", "Bernd", "44", "Bonn"})); |
| lvwPerson.Items.Add(new ListViewItem(new string[] |
| {"Berenbach", "Peter", "35", "Köln"})); |
| lvwPerson.Items.Add(new ListViewItem(new String[] |
| {"Keser", "Wolfgang", "48", "Düren"})); |
Mit spezifischen Eigenschaften ist der Typ ListViewSubItem-Klasse nicht besonders reichlich gesegnet. Neben der Eigenschaft Text, welche die textuelle Beschreibung des Unterelements enthält, gibt es nur noch die Eigenschaften BackColor, ForeColor und Font, um der Anzeige zur Laufzeit ein anderes oder vielleicht auch nur ansprechenderes Aussehen zu verleihen.
Neben der internen Auflistung ListViewItemCollection verfügt die ListView-Klasse über die schon weiter oben erwähnte Auflistung ColumnHeaderCollection, in der alle Spaltenköpfe vom Typ ColumnHeader aufgelistet sind. Diese werden nur in der Detailansicht angezeigt. Die Referenz auf die interne Auflistung liefert die Eigenschaft Columns. Auch für die Spaltendefinitionen stellt Visual Studio 2005 einen intuitiv zu bedienenden Assistenten zur Verfügung, der Ihnen das einfache Hinzufügen und Beschreiben der Spalten ermöglicht.
Ein Spaltenkopf wird nur durch wenige Eigenschaften beschrieben: Text legt die Beschriftung der Spalte fest, Width die Breite der Spalte und TextAlign die Ausrichtung der Spaltenüberschrift in der Spalte. Sie können im Spaltenkopf auch Symbole zeigen lassen. Dazu wertet das Objekt die Eigenschaft SmallImageList der ListView aus. Das einer Spalte zuzuordnende Bildchen tragen Sie in einer der beiden Eigenschaften ImageIndex oder ImageKey ein.
Über die schreibgeschützte Eigenschaft Index lässt sich die Position der Spalte innerhalb der ColumnHeaderCollection ermitteln. Der Wert entspricht nicht zwangsläufig der sichtbaren Position des Spaltenkopfes, denn wenn die Eigenschaft AllowColumnReorder der Listenansicht auf true eingestellt ist, kann der Anwender die Anzeigereihenfolge nach eigenem Ermessen festlegen.
| Eigenschaft | Beschreibung |
| ImageIndex | Ruft den Index des in der Spalte angezeigten Bilds ab oder legt diesen fest. |
| ImageKey | Ruft den Schlüssel des in der Spalte angezeigten Bilds ab oder legt diesen fest. |
| Index | Liefert die Position innerhalb der ColumnHeaderCollection zurück. |
| Text | Legt den im Spaltenkopf angezeigten Text fest oder ruft ihn ab. |
| TextAlign | Legt die horizontale Ausrichtung des in ColumnHeader angezeigten Textes fest oder ruft sie ab. |
| Width | Legt die Breite der Spalte fest oder ruft sie ab. |
Im .NET Framework 2.0 wurde das Steuerelement ListView um ein sehr interessantes Feature ergänzt. Sie können nun alle angezeigten Elemente visuell logischen Gruppen zuordnen. Jede einzelne Gruppe wird durch einen Text beschrieben, der beliebig ausgerichtet werden kann. Gruppen sind vom Typ der Klasse ListViewGroup.
Die Gruppen eines ListView-Steuerelements werden, da es sich in der Regel um mehrere handelt, von einer Auflistung verwaltet, deren Referenz die Eigenschaft Groups des Steuerelements bereitstellt. Ein Assistent erleichtert Ihnen auch hier die Arbeit. Jedes Listenelement muss nach spezifischen Kriterien einer Gruppe zugeordnet werden, die Sie selbst festlegen können.
Sie weisen ein Element einer Gruppe zu, indem Sie die Gruppe im ListViewItem-Konstruktor angeben, die ListViewItem.Group-Eigenschaft festlegen oder das Element direkt der Items-Auflistung einer Gruppe hinzufügen. Alle Elemente, die keiner Gruppe zugewiesen sind, werden in der Standardgruppe angezeigt, welche die Header-Bezeichnung Default trägt.
| Eigenschaft | Beschreibung |
| Header | Legt die Beschriftung der Gruppe fest. |
| HeaderAlignment | Legt die Ausrichtung der Beschriftung fest. |
| Items | Ruft eine Auflistung mit allen Elementen ab, die dieser Gruppe zugeordnet sind. |
| Name | Legt den Namen der Gruppe fest. |
Entwickeln wir die Personenauflistung, die weiter oben begonnen wurde, weiter, wäre eine Gruppierung nach Altersklassen denkbar. Um jede Person einer Altersgruppe zuzuordnen, könnte man mit
| foreach (ListViewItem item in lvwPerson.Items) |
| setGroup(item); |
alle Listenelemente abgreifen und in der benutzerdefinierten Methode setGroup über die Gruppenzugehörigkeit entscheiden.
| private void setGroup(ListViewItem item) { |
| if (Convert.ToInt32(item.SubItems[2].Text) < 31) |
| item.Group = lvwPerson.Groups[0]; |
| else if(Convert.ToInt32(item.SubItems[2].Text) < 41) |
| item.Group = lvwPerson.Groups[1]; |
| else |
| item.Group = lvwPerson.Groups[2]; |
| } |
Sie können dem Benutzer auch die Entscheidung darüber, ob er die Gruppierung der Listenelemente bevorzugt oder nicht, auch selbst überlassen. Die Anzeige lässt sich nämlich mit der Eigenschaft ShowGroups der Listenansicht beeinflussen. Per Vorgabe ist true eingestellt.

Hier klicken, um das Bild zu vergrößern
Abbildung 19.26 Ausgabe von Gruppierungen
ListView ermöglicht die Sortierung der Listeneinträge. Dazu müssen Sie der Eigenschaft Sorting, die vom Typ der Enumeration SortOrder ist, einen Wert zuweisen, der von der Vorgabe None abweicht. Alternativ können Sie eine aufsteigende Sortierreihenfolge mit Ascending und eine absteigende mit Descending erreichen. Das Kriterium der Sortierung sind dabei immer die Listenelemente, nicht die Unterelemente.
Wenn Sie sich den Windows Explorer vor Augen halten, wissen Sie, dass bei einem Klick auf einen Spaltenkopf die Sortierreihenfolge der Listeneinträge anhand der Unterelemente in der angeklickten Spalte erfolgt. Das ist auch in einer ListView sehr einfach zu realisieren und braucht nur wenig Programmcode. Voraussetzung dafür ist, dass die Einstellung der Eigenschaft HeaderStyle=Clickable ist. Das ist gleichzeitig auch der Standard.
Zuständig für eine vom Standard abweichende Sortierung ist die Eigenschaft ListViewItemSorter, die nicht im Eigenschaftsfenster der Entwicklungsumgebung angezeigt wird:
| public IComparer ListViewItemSorter {get; set;} |
Wir müssen der Eigenschaft ein Objekt übergeben, das die Schnittstelle IComparer implementiert. Uns kommt dabei entgegen, dass alle Einträge in der Listenansicht vom Typ string sind. Daher benötigen wir nicht für jede Spalte eine eigene Vergleichsklasse, sondern kommen, wenn wir es geschickt anstellen, mit einer einzigen aus. In der Vergleichsklasse sollten wir auch noch eine übliche Verhaltensweise berücksichtigen: Wird ein Spaltenkopf ein zweites Mal angeklickt, kehrt sich die Sortierreihenfolge der Listenelemente um.
Ein Klasse, die alle Ansprüche erfüllt, kann wie folgt codiert werden:
| public class ListViewComparer : IComparer { |
| private int col; |
| private SortOrder order; |
| public ListViewComparer(int col, SortOrder order) { |
| this.col = col; |
| this.order = order; |
| } |
| public int Compare(object x, object y) { |
| ListViewItem item1, item2; |
| item1 = (ListViewItem)x; |
| item2 = (ListViewItem)y; |
| if(this.order == SortOrder.Ascending) |
| return item1.SubItems[col].Text.CompareTo (item2.SubItems[col].Text); |
| else |
| return |
| item2.SubItems[col].Text.CompareTo(item1.SubItems[col].Text); |
| } |
| } |
Um die Allgemeingültigkeit der Klasse zu gewährleisten, übergeben wir dem Konstruktor sowohl den Index der angeklickten Spalte als auch die gewünschte Sortierreihenfolge. Diese Informationen werden von der Methode Compare als Grundlage des Vergleichs benötigt, der zwei Objekte vom Typ ListViewItem übergeben werden. Es stellt sich nun positiv heraus, dass das etwas eigenartige Verhalten eines ListViewItem-Objekts, sich in seine eigene ListViewSubItemCollection einzutragen, nun für uns von großem Nutzen ist. Auch die konstante Indizierung der Spaltenköpfe, die nicht zwangsläufig der sichtbaren Reihenfolge entspricht (wenn AllowColumnReorder=true eingestellt ist), macht die Vergleichsoperation denkbar einfach.
Bei genauer Betrachtung hat die Klassendefinition sogar einen allgemeinen Charakter und kann, wenn keine besonderen Vergleichskriterien eine Rolle spielen, praktisch von jeder Listenansicht benutzt werden.
Wir wollen jetzt die Liste der Personen, der wir uns im Laufe des Abschnitts schon einige Male bedient haben, vervollständigen und im ListView auch die Spaltensortierung vorsehen.
| // --------------------------------------------------------- |
| // Beispiel: ...\Kapitel 19\SortedColumns |
| // --------------------------------------------------------- |
| ... |
| private void lvwPerson_ColumnClick(object sender, ColumnClickEventArgs e) { |
| if(lvwPerson.Sorting == SortOrder.Ascending) { |
| lvwPerson.Sorting = SortOrder.Descending; |
| lvwPerson.ListViewItemSorter = |
| new ListViewComparer(e.Column, SortOrder.Descending); |
| } |
| else { |
| lvwPerson.Sorting = SortOrder.Ascending; |
| lvwPerson.ListViewItemSorter = |
| new ListViewComparer(e.Column, SortOrder.Ascending); |
| } |
| } |
| private void btnAddPerson_Click(object sender, EventArgs e) { |
| string[] newPerson = { "Hamster", "Karl", "34", "Bremen" }; |
| lvwPerson.Items.Add(new ListViewItem(newPerson)); |
| setGroup(lvwPerson.Items[lvwPerson.Items.Count – 1]); |
| btnAddPerson.Enabled = false; |
| } |
| private void btnShowGroups_Click(object sender, EventArgs e) { |
| if (lvwPerson.ShowGroups) { |
| lvwPerson.ShowGroups = false; |
| btnShowGroups.Text = "Gruppierung einblenden"; |
| } |
| else { |
| lvwPerson.ShowGroups = true; |
| btnShowGroups.Text = "Gruppierung ausblenden"; |
| } |
| } |
Um die Sortierreihenfolge zu ändern, klickt der Anwender auf einen Spaltenkopf. Dabei wird das Ereignis ColumnClick ausgelöst, das in der Eigenschaft Column des Args-Parameters den Index des angeklickten Spaltenkopfs bereitstellt. Weil die Sortierreihenfolge bei jedem Anklicken umgekehrt werden soll, muss die aktuelle Einstellung der Eigenschaft Sorting zunächst überprüft und danach negiert werden. Anschließend kann die Vergleichsklasse unter Übergabe der entsprechenden Parameter instanziiert und der Eigenschaft ListViewItemSorter übergeben werden.
Um zu testen, wie sich das Hinzufügen eines weiteren Listenelements auf die Sortierreihenfolge auswirkt, enthält die Form außerdem noch eine Schaltfläche, die den entsprechenden Code aufweist. Sie werden feststellen, dass das neue Listenelement an der richtigen Position eingefügt wird. Sehr erfreulich ist auch, dass in der Gruppierungsansicht innerhalb einer Gruppe sich die Sortierreihenfolge richtig einstellt.
| Hinweis Ergänzen Sie die Listenansicht mit vielen Elementen unter Aufruf der Add-Methode, wird das Steuerelement jedes Mal neu gezeichnet. Möglicherweise kann das zum Flackern der Anzeige führen. Sie können das vermeiden, wenn Sie vor dem Hinzufügen der neuen Listenelemente mit der Methode BeginUpdate das wiederholte Neuzeichnen unterdrücken. Nach dem Hinzufügen des letzten Listenelements müssen Sie das ListView-Objekt mit EndUpdate jedoch neu aufbauen. |
Standardmäßig werden die Listenelemente nur angezeigt und können nicht verändert werden. Mit der Eigenschaft LabelEdit=true der Listenansicht können Sie einem Anwender jedoch einräumen, den Text des Listenelements zu editieren. Zur Laufzeit muss das zu ändernde Listenelement zunächst mit einem Klick markiert werden. Beim nächsten Klick befindet sich der Eingabecursor am Ende des Textes. Eine Möglichkeit, auch den Inhalt der Unterelemente zu verändern, gibt es nicht.
Eine Änderung hat nicht zur Folge, dass auch die zugrunde liegenden Daten geändert werden, wenn eine ListView beispielsweise die Listenelemente aus einer Datenbank bezogen hat. Im Kontext mit dem Zurückschreiben von Änderungen bieten sich zwei Ereignisse an: BeforeLabelEdit und AfterLabelEdit. Das erste wird ausgelöst, sobald das Listenelement das zweite Click-Ereignis registriert hat und editierfähig geworden ist, das zweite Ereignis wird beim Verlassen der Eingabebox ausgelöst.
Beide Ereignisse stellen dem Ereignishandler im zweiten Parameter ein Objekt vom Typ LabelEditEventArgs zur Verfügung. Mit der Eigenschaft CancelEdit kann die Operation abgebrochen werden, Item ruft den Index des zur Änderung anstehenden ListViewItem-Objekts ab und Label beinhaltet die Zeichenfolge, die der Text-Eigenschaft des Listenelements zugewiesen werden soll.
Um Daten in die Originaldatenquelle zurückzuschreiben, werden Sie den AfterLabelEdit-Ereignishandler codieren. Hier bietet es sich an, beispielsweise eine Eingabeüberprüfung vorzunehmen. Die Eigenschaft Label liefert die zur Überprüfung notwendige Information. Brechen Sie die Operation mit CancelEdit=true ab, wird der ursprüngliche Inhalt automatisch wiederhergestellt.
Wenn Sie bis hierher aufmerksam gefolgt sind, werden Sie vermutlich den Eindruck haben, dass das ListView-Steuerelement sehr kompliziert zu programmieren ist. Es beinhaltet eine große Anzahl von Klassen und eine Fülle von Eigenschaften. Wie komplex die Bereitstellung einer Listenansicht letztendlich wird, hängt natürlich von den Anforderungen ab, die Sie an das Laufzeitverhalten stellen. Dient es nur der einfachen Ansicht von Informationen, ist die Programmierung recht einfach, wollen Sie aber einen ganz individuellen Explorer programmieren, steigt der Aufwand immens an.
Ich möchte Ihnen nun das Beispiel ExplorerApplication vorstellen, das einen Teil der vom Windows Explorer gewohnten Verhaltensweisen zeigt. Dazu wird das Beispiel Verzeichnisstruktur erweitert, das im Zusammenhang mit dem TreeView-Steuerelement entwickelt wurde. Das Beispielprogramm soll und kann kein vollwertiger Ersatz des Microsoft Explorers sein, aber dennoch die wichtigsten Aspekte berücksichtigen. Wenn Sie Lust haben, können Sie natürlich den Code beliebig weiterentwickeln.
Wie sich das Beispiel zur Laufzeit zeigt, können Sie der folgenden Abbildung entnehmen.
Bevor wir uns den Programmcode ansehen, muss zunächst das Laufzeitverhalten der Anwendung erläutert werden.
Nach dem Start wird zunächst das Laufwerk C:\ ausgewählt, und dazu werden die diesem Laufwerk zugeordneten Verzeichnisse und Dateien in der Listenansicht angezeigt. Eine Änderung der Auswahl zieht auch die Anpassung in der Listenansicht nach sich. Die Listenelemente dienen jedoch nicht nur der Ansicht, sie reagieren auch auf die Aktivierung mit einem Doppelklick, denn das Standardverhalten wird beibehalten. Wird zum Beispiel eine EXE-Datei aktiviert, wird die entsprechende Anwendung gestartet. Handelt es sich um eine Dokumentdatei, wird diese innerhalb der zugeordneten Applikation geöffnet.

Hier klicken, um das Bild zu vergrößern
Abbildung 19.27 Ausgabe des Beispiels »ExplorerApplication«
Damit nicht genug, auch die Verzeichniseinträge in der Listenansicht reagieren auf die Aktivierung durch den Anwender. Ein Doppelklick auf ein Verzeichnis öffnet das Verzeichnis in der Listenansicht und passt gleichzeitig auch die Ansicht des TreeView-Steuerelements der neuen Auswahl an.
Im TreeView-Steuerelement können die lokalen Laufwerke und Ordner ausgewählt werden. Die Auswahl spiegelt sich im ListView-Steuerelement wider, das neben den Unterverzeichnissen auch alle Dateien des in der Strukturansicht ausgewählten Verzeichnisses anzeigt.
In der Menüleiste kann unter Ansicht die Darstellungsform der Listenansicht beliebig in Kleine Symbole, Große Symbole, Liste und Details verändert werden. In der Form befinden sich zwei ImageList–Objekte, welche die kleinen und großen Symbole enthalten. Die Dateien der Symbole selbst sind in einem eigenen Ordner unterhalb des Projektordners zu finden. Beide Bildlisten werden über die entsprechenden Eigenschaften der Listenansicht (LargeImageList und SmallImageList) referenziert.
Kommen wir nun zum Programmcode.
| // --------------------------------------------------------- |
| // Beispiel: ...\Kapitel 19\ExplorerApplication |
| // --------------------------------------------------------- |
| ... |
| public Form1() { |
| InitializeComponent(); |
| // Initialisierung des TreeView-Steuerelements |
| } |
Vergleichen Sie den Konstruktor der Form, werden Sie keinen Unterschied zu dem des Beispiels Ordnerstruktur feststellen. Dennoch hat die Initialisierung des TreeView-Steuerelements eine wichtige Konsequenz: Sobald das Laufwerk C:\ nach dem Start der Anwendung ausgewählt wird, sollten dessen Ordner und Dateien bereits in der Listenansicht angezeigt werden. Dazu bietet sich grundsätzlich das Ereignis AfterSelect des TreeView-Objekts an, das immer dann ausgelöst wird, wenn in der Strukturansicht ein neues Element ausgewählt worden ist.
| private TreeNode activeNode; |
| ... |
| private void treeView_AfterSelect(object sender, TreeViewEventArgs e) { |
| ... |
| activeNode = e.Node; |
| this.GetAllDirAndFileInfos(); |
| } |
Der aktuelle Knoten – nach dem Start also C:\ – wird in einer Variablen gespeichert, weil er später noch benötigt wird. Der Methode GetAllDirAndFileInfos kommt eine wichtige Bedeutung zu: Sie sondiert die Unterverzeichnisse und Dateien des im TreeView ausgewählten Knotens und liest außerdem die spezifischen Eigenschaften der einzelnen Objekte ein, bei den Dateien beispielsweise die Größe, das Datum der letzten Änderung und die Dateiattribute. Für jedes eingelesene Element wird ein neues ListViewItem-Objekt erstellt.
| private void GetAllDirAndFileInfos() { |
| listView.Items.Clear(); |
| ListViewItem item; |
| DirectoryInfo dirInfo = |
| new DirectoryInfo(treeView.SelectedNode.FullPath); |
| try { |
| // --------- Unterverzeichnisse ----------- |
| foreach(DirectoryInfo dir in dirInfo.GetDirectories()) { |
| item = listView.Items.Add(" " + dir.Name, 1); |
| item.SubItems.Add(""); |
| item.SubItems.Add(dir.LastWriteTime.ToString()); |
| } |
| // ------------------ Dateien -------------- |
| foreach(FileInfo file in dirInfo.GetFiles()) { |
| item = listView.Items.Add(file.Name, 2); |
| item.SubItems.Add(file.Length.ToString()); |
| item.SubItems.Add(file.LastWriteTime.ToString()); |
| // Dateiattribute ermitteln |
| string fileAttributes = ""; |
| if((file.Attributes & FileAttributes.Archive) != 0) |
| fileAttributes += "A"; |
| if((file.Attributes & FileAttributes.Hidden) != 0) |
| fileAttributes += "H"; |
| if((file.Attributes & FileAttributes.ReadOnly) != 0) |
| fileAttributes += "R"; |
| if((file.Attributes & FileAttributes.System) != 0) |
| fileAttributes += "S"; |
| item.SubItems.Add(fileAttributes); |
| } |
| } |
| catch { |
| return; |
| } |
| } |
ItemActivate wird bei der Aktivierung eines oder mehrerer Listenelementen ausgelöst. Damit wir diese Elemente ansprechen können, durchlaufen wir im Ereignishandler die Auflistung SelectedListViewItemCollection in einer foreach-Schleife, in der wir die Eigenschaft SelectedItems abrufen. In der Schleife muss zuerst überprüft werden, ob es sich bei dem augenblicklich referenzierten Listenelement um ein Verzeichnis oder eine Datei handelt. Steht das Objekt für ein Verzeichnis, wird die Ansicht des TreeView-Steuerelements angepasst und der entsprechende Knoten expandiert (die Reduktion ist in diesem Beispiel nicht codiert!).
Handelt es sich bei dem ausgewählten Element in der Listenansicht um eine Datei, wird mit
| Process.Start(path); |
die statische Methode Start der Klasse Process aufgerufen. Die im Argument angegebene Datei wird gestartet, falls es sich um eine EXE-Datei handelt. Ist es eine Dokumentdatei, wird die zu dem Dateityp registrierte Anwendung gestartet und darin die Dokumentdatei zur Bearbeitung geöffnet. Beachten Sie, dass die Klasse Process im Namespace System.Diagnostics definiert ist, der mit using bekannt gegeben wird.
| private void listView_ItemActivate(object sender, EventArgs e) { |
| foreach(ListViewItem item in listView.SelectedItems) { |
| string path = treeView.SelectedNode.FullPath; |
| path = path + "\\" + item.Text; |
| // prüfen, ob die Wahl auf ein Verzeichnis gefallen ist |
| FileInfo fileInfo = new FileInfo(path); |
| if(0 != (fileInfo.Attributes | FileAttributes.Directory)) { |
| // gewähltes Element ist ein Verzeichnis |
| foreach(TreeNode node in activeNode.Nodes) { |
| if(item.Text.Trim() == node.Text.Trim()) { |
| treeView.SelectedNode = node; |
| treeView.SelectedNode.Expand(); |
| activeNode = node; |
| treeView.Refresh(); |
| return; |
| } |
| } |
| } |
| else { |
| try { |
| Process.Start(path); |
| } |
| catch {return;} |
| } |
| } |
| } |
Die Methode SetView ist der Ereignishandler der Click-Ereignisse der Menüpunkte, mit denen im ListView zwischen den verschiedenen Ansichten gewechselt werden kann.
| private void SetView(object sender, System.EventArgs e) { |
| if (sender == mnuSmallIcons) |
| listView.View = View.SmallIcon; |
| else if (sender == mnuLargeIcons) |
| listView.View = View.LargeIcon; |
| else if (sender == mnuListe) |
| listView.View = View.List; |
| else if (sender == mnuDetails) |
| listView.View = View.Details; |
| } |
| << zurück |
|
||||||||||||||
|
||||||||||||||
|
||||||||||||||
|
||||||||||||||
Copyright © Galileo Press 2006
Für Ihren privaten Gebrauch dürfen Sie die Online-Version natürlich ausdrucken. Ansonsten unterliegt das <openbook> denselben Bestimmungen, wie die gebundene Ausgabe: Das Werk einschließlich aller seiner Teile ist urheberrechtlich geschützt. Alle Rechte vorbehalten einschließlich der Vervielfältigung, Übersetzung, Mikroverfilmung sowie Einspeicherung und Verarbeitung in elektronischen Systemen.